home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / PowerPlant / LTimeDateControl 1.0 / LTimeDateControl.cp next >
Encoding:
Text File  |  1995-12-09  |  22.8 KB  |  888 lines  |  [TEXT/CWIE]

  1. //
  2. //    LTimeDateControl v1.0
  3. //        A time and date picker for Power Plant.
  4. //
  5. //    Copyright © 1995 by Michael F. Kamprath
  6. //        mailto:kamprath@kagi.com
  7. //        http://www.leonardo.net/kamprath/claireware.html
  8. //
  9. //    Abstract
  10. //    --------
  11. //
  12. //    LTimeDateControl is a drop in module to give your Power Plant based application an
  13. //    easy to use, graphical time and/or date picker. The user interface of LTimeDateControl
  14. //    allows a user to click on a portion of a date and/or time string, and then change it's
  15. //    value by clicking on an arrow or with the arrow keys.
  16. //
  17. //    ConOps
  18. //    ------
  19. //
  20. //    To use, add a LControl pane to a view in your application and make it's class ID 'TmDt'.
  21. //    Fill out it's values as you would a normal LControl with the following exceptions:
  22. //
  23. //        1.     Min, Max, and Initial vlaue of the LControl is ignored. LTimeDateControl does
  24. //            not use LControl's value tracking mechanism.
  25. //
  26. //        2.    The user constant must be set to the variation of the LTimeDateControl you wish
  27. //            to use. Variation IDs are:
  28. //
  29. //                    Type                |    ID
  30. //                    ===========================
  31. //                    Time only            |    1
  32. //                    Long Date only        |    2
  33. //                    Long Date & Time    |    3
  34. //                    Short Date only        |    4    (not supported yet in v1.0)
  35. //                    Short Date & Time    |    5    (not supported yet in v1.0)
  36. //
  37. //        3.    You may set a text traits ID for LTimeDateControl, but you must ensure the 
  38. //            frame you define for LTimeDateControl is at least the font's height plu 5 pixels
  39. //            and an appropiate width to contain the date/time string plus 20 pixels in
  40. //            width. Some expirementation will probably be needed to get the look you want.
  41. //
  42. //    LTimeDateControl ignores LControl's value tracking mechanism in favor of it's
  43. //    own. You may track a LTimeDateControl's value in either seconds (unsigned long)
  44. //    or by a DateTimeRec. You may get the current value of LTimeDateControl with:
  45. //
  46. //            Uint32            LTimeDateControl::GetDateTimeValue( void )
  47. //            DateTimeRec        LTimeDateControl::GetDateTimeRec( void )
  48. //
  49. //    And set the current value with:
  50. //
  51. //            void            LTimeDateControl::SetDateTimeValue( const Uint32& inValue )
  52. //            void            LTimeDateControl::SetDateTimeValue( const DateTimeRec& inRec )
  53. //    
  54. //    When ever the user changes a LTimeDateControl value (note, not when it is 
  55. //    programatically changed), LTimeDateControl broadcasts a msg_TimeDateHasChanged
  56. //    message (defined in LTimeDateControl.h) to any LListener's attached to the
  57. //    LTimeDateControl. In the ioParameter of the message, the LTimeDateControl's pane 
  58. //    ID is passed.
  59. //
  60. //    LTimeDateControl inherits off of LCommander (along with LControl) so that it will
  61. //    de-hilite the currently selected date portion when it is no longer "in focus" and
  62. //    to get keyDown messages. 
  63. //
  64. //    LTimeDateControl utilizes a StOffscreenGWorld so that a "smooth" redraw will be done.
  65. //    Be sure to include the PowerPlant file "UGWorld.cp" in your project. LTimeDateControl
  66. //    honors it's parent view's background color where appropiate (ensure that a call to
  67. //    ApplyForeAndBackColors() will properly set it at the time of LTimeDateControl redraw).
  68. //
  69. //    Be sure to also include the file LTimeDateControl.rsrc in your project. It contains
  70. //    the control's arrow icons. Of course, you can change them to maintain your "look and feel"
  71. //
  72. //    Legalisms
  73. //    ---------
  74. //
  75. //    You may freely use LTimeDateControl with the following exceptions:
  76. //
  77. //        1.    If you use LTimeDateControl in your project, e-mail me so that I can keep you
  78. //            posted when I release new versions.
  79. //        2.    If you use LTimeDateControl in a project that you release to the public and 
  80. //            charge money for, I ask for a free & registered version of the product.
  81. //        3.    No derivatives of LTimeDateControl may be publicly release with out my consent.
  82. //
  83.  
  84. #include <TextUtils.h>
  85. #include <Icons.h>
  86. #include <string.h>
  87. #include <LString.h>
  88. #include <UGWorld.h>
  89. #include <UDrawingState.h>
  90. #include <UTextTraits.h>
  91. #include "LTimeDateControl.h"
  92.  
  93. static void    HiliteRect(Rect *theRect);
  94.  
  95. const short        kTimeStringPos        =    5;
  96. const short        kButtonIconHeight    =    16;
  97. const short        kButtonIconWidth    =    16;
  98. const ResIDT    kArrowButtonID        =    15000;
  99.  
  100. LTimeDateControl*
  101. LTimeDateControl::CreateTimeDateControlStream(    LStream    *inStream)
  102. {
  103.     return (new LTimeDateControl(inStream));
  104. }
  105.  
  106. LTimeDateControl::LTimeDateControl()
  107.     :    LControl(),
  108.         mDateTimeValue(0)
  109. {
  110.     this->InitDateTimeControl();
  111. }
  112. LTimeDateControl::LTimeDateControl(    const LTimeDateControl &inOriginal)
  113.     :    LControl(inOriginal),
  114.         mDateTimeValue(0)
  115. {
  116.     this->InitDateTimeControl();
  117. }
  118. LTimeDateControl::LTimeDateControl(    const SPaneInfo &inPaneInfo,
  119.                                     MessageT inValueMessage, 
  120.                                     Uint32 inDateTimeValue,
  121.                                     LTimeDateControl::ETimeDateControlType inVariation )
  122.     :    LControl(inPaneInfo,inValueMessage, 0, 0, 256),
  123.         mVariation( inVariation ),
  124.         mDateTimeValue(inDateTimeValue)
  125. {
  126.     this->InitDateTimeControl();
  127. }
  128. LTimeDateControl::LTimeDateControl(    LStream *inStream)
  129.     :    LControl(inStream),
  130.         mDateTimeValue(0)
  131. {
  132.     this->InitDateTimeControl();
  133. }
  134.  
  135. LTimeDateControl::~LTimeDateControl()
  136. {
  137.     if (this->mTimeFormatH)
  138.         ::DisposeHandle( (Handle)this->mTimeFormatH );
  139.     if (this->mDateFormatH)
  140.         ::DisposeHandle( (Handle)this->mDateFormatH );
  141. }
  142.  
  143. void
  144. LTimeDateControl::InitDateTimeControl( void )
  145. {
  146.     this->mCntlTextTraitsID = this->GetMinValue();
  147.  
  148.     this->mVariation = (ETimeDateControlType)this->GetUserCon();
  149.     this->mTimeFormatH = nil;
  150.     this->mDateFormatH = nil;
  151.     this->mCurrentHilite = 0;
  152.     
  153.     this->mTimeFormatH = (Intl0Hndl)::GetIntlResource( 0 );
  154.     ::DetachResource( (Handle)this->mTimeFormatH );
  155.     ::HNoPurge( (Handle)this->mTimeFormatH );
  156.     (*this->mTimeFormatH)->timeFmt |= secLeadingZ | minLeadingZ | hrLeadingZ;
  157.  
  158.     this->mDateFormatH = (Intl1Hndl)::GetIntlResource( 1 );
  159.     ::DetachResource( (Handle)this->mDateFormatH );
  160.     ::HNoPurge( (Handle)this->mDateFormatH );
  161.     (*this->mDateFormatH)->dayLeading0 = 255;
  162.     this->InitDateStarts();
  163.     
  164. }
  165.  
  166. void 
  167. LTimeDateControl::InitDateStarts( void )
  168. {
  169. short        abbrLen, posNum, prevPosNum;
  170. short        st0, st1, st2, st3;
  171.  
  172.     st0 = ::strlen( (*this->mDateFormatH)->st0 );
  173.     st1 = ::strlen( (*this->mDateFormatH)->st1 );
  174.     st2 = ::strlen( (*this->mDateFormatH)->st2 );
  175.     st3 = ::strlen( (*this->mDateFormatH)->st3 );
  176.  
  177.     st0 = ( st0 < 4 ) ? st0 : 4;
  178.     st1 = ( st1 < 4 ) ? st1 : 4;
  179.     st2 = ( st2 < 4 ) ? st2 : 4;
  180.     st3 = ( st3 < 4 ) ? st3 : 4;
  181.     
  182.     abbrLen = (*this->mDateFormatH)->abbrLen;
  183.         
  184.     if ( (*this->mDateFormatH)->lngDateFmt == 255 )
  185.     {        
  186.         /* day name */
  187.         this->mStartArray[ 1 ] = st0;
  188.         if ( (*this->mDateFormatH)->suppressDay == 255 )
  189.             this->mEndArray[ 1 ] = this->mStartArray[ 1 ];
  190.         else
  191.             this->mEndArray[ 1 ] = this->mStartArray[ 1 ] + abbrLen;
  192.  
  193.         /* month name */
  194.         this->mStartArray[ 2 ] = this->mEndArray[ 1 ] + st1;
  195.         this->mEndArray[ 2 ] = this->mStartArray[ 2 ] + abbrLen;
  196.  
  197.         /* date number */
  198.         this->mStartArray[ 0 ] = this->mEndArray[ 2 ] + st2;
  199.         this->mEndArray[ 0 ] = this->mStartArray[ 0 ] + 2;
  200.         
  201.         /* year */
  202.         this->mStartArray[ 3 ] = this->mEndArray[ 0 ] + st3;
  203.         this->mEndArray[ 3 ] = this->mStartArray[ 3 ] + 4;
  204.         
  205.     }
  206.     else
  207.     {
  208.         
  209.         
  210.         /* first position */
  211.         posNum = ( ((*this->mDateFormatH)->lngDateFmt)&3 );
  212.         this->mStartArray[posNum] = st0 ;
  213.         if (posNum == 0 ) /* date number */
  214.             this->mEndArray[posNum] = this->mStartArray[posNum] + 2;
  215.         else if (posNum == 3 ) /* year item */
  216.             this->mEndArray[posNum] = this->mStartArray[posNum] + 4;
  217.         else
  218.             this->mEndArray[posNum] = this->mStartArray[posNum] + abbrLen;
  219.         
  220.         /* second position */
  221.         prevPosNum = posNum;
  222.         posNum = ( ((*this->mDateFormatH)->lngDateFmt)&12 )/4;            
  223.         this->mStartArray[posNum] = this->mEndArray[prevPosNum] + st1 ;
  224.         if (posNum == 0 ) /* date number */
  225.             this->mEndArray[posNum] = this->mStartArray[posNum] + 2;
  226.         else if (posNum == 3 ) /* year item */
  227.             this->mEndArray[posNum] = this->mStartArray[posNum] + 4;
  228.         else
  229.             this->mEndArray[posNum] = this->mStartArray[posNum] + abbrLen;
  230.         
  231.         /* third position */
  232.         prevPosNum = posNum;
  233.         posNum = ( ((*this->mDateFormatH)->lngDateFmt)&48 )/16;
  234.         this->mStartArray[posNum] = this->mEndArray[prevPosNum] + st2 ;
  235.         if (posNum == 0 ) /* date number */
  236.             this->mEndArray[posNum] = this->mStartArray[posNum] + 2;
  237.         else if (posNum == 3 ) /* year item */
  238.             this->mEndArray[posNum] = this->mStartArray[posNum] + 4;
  239.         else
  240.             this->mEndArray[posNum] = this->mStartArray[posNum] + abbrLen;
  241.     
  242.         /* fourth position */
  243.         prevPosNum = posNum;
  244.         posNum = ( ((*this->mDateFormatH)->lngDateFmt)&192 )/64;
  245.         
  246.         this->mStartArray[posNum] = this->mEndArray[prevPosNum] + st3 ;
  247.         if (posNum == 0 ) /* date number */
  248.             this->mEndArray[posNum] = this->mStartArray[posNum] + 2;
  249.         else if (posNum == 3 ) /* year item */
  250.             this->mEndArray[posNum] = this->mStartArray[posNum] + 4;
  251.         else
  252.             this->mEndArray[posNum] = this->mStartArray[posNum] + abbrLen;
  253.         
  254.     
  255.     }
  256.     
  257. }    
  258.  
  259. void        
  260. LTimeDateControl::ClickSelf(const SMouseDownEvent &inMouseDown)
  261. {
  262.     if (!this->IsTarget()) 
  263.         this->SwitchTarget(this);
  264.  
  265.     this->LControl::ClickSelf(inMouseDown);
  266. }
  267. void        
  268. LTimeDateControl::BeTarget()
  269. {
  270. }
  271.  
  272. void        
  273. LTimeDateControl::DontBeTarget()
  274. {
  275.     this->mCurrentHilite = 0;
  276.     this->FocusDraw();
  277.     this->DrawDateTimeControl();
  278. }
  279. void        
  280. LTimeDateControl::ActivateSelf()
  281. {
  282.     this->FocusDraw();
  283.     this->DrawDateTimeControl();
  284. }
  285. void
  286. LTimeDateControl::DeactivateSelf()
  287. {
  288.     this->FocusDraw();
  289.     this->DrawDateTimeControl();
  290. }
  291.  
  292. Boolean        
  293. LTimeDateControl::HandleKeyPress( const EventRecord    &inKeyEvent)
  294. {
  295. Boolean        returnVal = false;
  296. Char16        theKey = inKeyEvent.message;
  297. Uint16         theHotSpot;
  298.  
  299.     switch (theKey & charCodeMask) 
  300.     {
  301.     
  302.         case char_UpArrow:
  303.             theHotSpot = kInUpArrow;
  304.             this->ArrowAction( theHotSpot, true );
  305.             this->HotSpotResult( theHotSpot );
  306.             returnVal = true;
  307.             break;
  308.         case char_DownArrow:
  309.             theHotSpot = kInDownArrow;
  310.             this->ArrowAction( theHotSpot, true );
  311.             this->HotSpotResult( theHotSpot );
  312.             returnVal = true;
  313.             break;
  314.         case char_LeftArrow:
  315.         case char_RightArrow:
  316.         default:
  317.             returnVal = this->LCommander::HandleKeyPress(inKeyEvent);
  318.             break;
  319.     }
  320.  
  321.     return returnVal;
  322. }
  323. Boolean        
  324. LTimeDateControl::FocusDraw()
  325. {
  326. Boolean    focused = LControl::FocusDraw();
  327.  
  328.     UTextTraits::SetPortTextTraits( this->mCntlTextTraitsID );
  329.     
  330.     return focused;
  331. }
  332. void
  333. LTimeDateControl::DrawSelf( )
  334. {
  335.     this->DrawDateTimeControl( );
  336. }
  337.  
  338. void
  339. LTimeDateControl::DrawDateTimeControl( const Uint16& theHotSpot )
  340. {
  341. Rect                 contrlRect, strRect, workRect;
  342. RGBColor            whiteColor = {0xFFFF,0xFFFF,0xFFFF};
  343. RGBColor            foreColor, backColor;
  344. Point                thePt;
  345. short                iconID;
  346.  
  347.     ::GetForeColor(&foreColor);
  348.     ::GetBackColor(&backColor);
  349.  
  350.     this->CalcLocalFrameRect( contrlRect );
  351.  
  352.     StOffscreenGWorld    offWorld(contrlRect);
  353.     
  354.     this->ApplyForeAndBackColors();
  355.     
  356.     strRect = contrlRect;
  357.     strRect.right = contrlRect.right - kTimeStringPos - kButtonIconWidth;
  358.     
  359.     if (this->IsActive())
  360.     {
  361.         ::EraseRect(&contrlRect);
  362.         ::RGBBackColor(&whiteColor);
  363.         ::EraseRect(&strRect);
  364.         ::FrameRect(&strRect);
  365.         
  366.         UTextTraits::SetPortTextTraits( this->mCntlTextTraitsID );
  367.         
  368.         thePt.h = strRect.left + kTimeStringPos;
  369.         thePt.v = strRect.bottom - 5;
  370.         
  371.         switch (this->mVariation)
  372.         {
  373.             case kTimeVariation:
  374.                 this->DrawTimeString( thePt, strRect, this->mCurrentHilite );
  375.                 break;
  376.             case kLongDateVariation:
  377.                 this->DrawLongDateString( thePt, strRect, this->mCurrentHilite );
  378.                 break;
  379.             case kLongDateAndTimeVariation:
  380.                 thePt.h += this->DrawLongDateString( thePt, strRect, this->mCurrentHilite ) + kTimeStringPos;
  381.                 this->DrawTimeString( thePt, strRect, this->mCurrentHilite );
  382.                 break;
  383.                 
  384.         }
  385.         
  386.         if (this->mCurrentHilite)
  387.         {
  388.             if (theHotSpot&kInUpArrow)
  389.                 iconID = kArrowButtonID + 1;
  390.             else if (theHotSpot&kInDownArrow)
  391.                 iconID = kArrowButtonID + 2;
  392.             else
  393.                 iconID = kArrowButtonID;
  394.                         
  395.             SetRect(&workRect,    strRect.right + kTimeStringPos, 
  396.                                 strRect.top + (strRect.bottom - strRect.top)/2 - kButtonIconHeight/2,
  397.                                 strRect.right + kTimeStringPos + kButtonIconWidth,
  398.                                 strRect.top + (strRect.bottom - strRect.top)/2 + kButtonIconHeight/2);
  399.             PlotIconID(&workRect, atVerticalCenter, ttNone, iconID);
  400.         }
  401.     }
  402.     else
  403.     {
  404.     RGBColor    foreColor, oldForColor, backColor;
  405.     GDHandle    devH;
  406.     
  407.         ::EraseRect(&contrlRect);
  408.         ::RGBBackColor(&whiteColor);
  409.         ::EraseRect(&strRect);
  410.         ::FrameRect(&strRect);
  411.         
  412.         UTextTraits::SetPortTextTraits( this->mCntlTextTraitsID );
  413.         thePt.h = strRect.left + kTimeStringPos;
  414.         thePt.v = strRect.bottom - 5;
  415.         
  416.         devH = ::GetGDevice(  );
  417.         ::GetForeColor( &foreColor );
  418.         oldForColor = foreColor;
  419.         ::GetBackColor( &backColor );
  420.         ::GetGray( devH, &backColor, &foreColor );
  421.         ::RGBForeColor( &foreColor );
  422.         
  423.         
  424.         switch (this->mVariation)
  425.         {
  426.             case kTimeVariation:
  427.                 this->DrawTimeString( thePt, strRect, 0 );
  428.                 break;
  429.             case kLongDateVariation:
  430.                 this->DrawLongDateString( thePt, strRect, 0 );
  431.                 break;
  432.             case kLongDateAndTimeVariation:
  433.                 thePt.h += this->DrawLongDateString( thePt, strRect, 0 ) + kTimeStringPos;
  434.                 this->DrawTimeString( thePt, strRect, 0 );
  435.                 break;
  436.         }
  437.         
  438.         ::RGBForeColor(&oldForColor);    
  439.     }
  440.     
  441.     
  442.     this->SetForeAndBackColors( &foreColor, &backColor );
  443. }
  444.  
  445. Int16
  446. LTimeDateControl::DrawTimeString(         const Point& startPos, 
  447.                                         const Rect& strRect,
  448.                                         const Uint16& hilite )
  449. {
  450. Str255    timeStr, tempStr;
  451. short    startH, endH;
  452. Rect    workRect;
  453.  
  454.     ::TimeString(this->mDateTimeValue, false, timeStr, (Handle)this->mTimeFormatH );
  455.     
  456.     ::MoveTo(startPos.h, startPos.v);
  457.     ::DrawString( timeStr );
  458.     
  459.     if (hilite&kTimeHiliteMask)
  460.     {
  461.         LString::CopyPStr( timeStr, tempStr);
  462.         if (hilite == kHourItem)
  463.         {
  464.             startH = 0;
  465.             tempStr[0] = 2;
  466.             endH = ::StringWidth(tempStr);
  467.         }
  468.         else if ( hilite == kMinuteItem )
  469.         {
  470.             if ((*mTimeFormatH)->timeSep)
  471.             {
  472.                 tempStr[0] = 3;
  473.                 startH = ::StringWidth(tempStr);
  474.                 tempStr[0] = 5;
  475.                 endH = ::StringWidth(tempStr);
  476.             }
  477.             else
  478.             {
  479.                 tempStr[0] = 2;
  480.                 startH = ::StringWidth(tempStr);
  481.                 tempStr[0] = 4;
  482.                 endH = ::StringWidth(tempStr);
  483.             }
  484.         }
  485.         else if ( hilite == kSecondItem )
  486.         {
  487.         }
  488.         else if ( hilite == kAMPMItem )
  489.         {
  490.             if ((*mTimeFormatH)->timeSep)
  491.             {
  492.                 tempStr[0] = 6;
  493.                 startH = ::StringWidth(tempStr);
  494.                 tempStr[0] = 8;
  495.                 endH = ::StringWidth(tempStr);
  496.             }
  497.             else
  498.             {
  499.                 tempStr[0] = 5;
  500.                 startH = ::StringWidth(tempStr);
  501.                 tempStr[0] = 7;
  502.                 endH = ::StringWidth(tempStr);
  503.             }
  504.         }
  505.         ::SetRect(&workRect, startH + startPos.h, strRect.top + 3, 
  506.                              endH + startPos.h, strRect.bottom - 2);
  507.         ::HiliteRect( &workRect );
  508.         
  509.     }
  510.     
  511.     return ::StringWidth( timeStr );
  512. }
  513. Int16
  514. LTimeDateControl::DrawLongDateString(    const Point& startPos, 
  515.                                         const Rect& strRect,
  516.                                         const Uint16& hilite )
  517. {
  518. Str255    dateStr, tempStr;
  519. short    startH, endH;
  520. Rect    workRect;
  521.     
  522.     
  523.     ::DateString( this->mDateTimeValue, abbrevDate, dateStr, (Handle)this->mDateFormatH);
  524.  
  525.     ::MoveTo(startPos.h, startPos.v);
  526.     ::DrawString( dateStr );
  527.  
  528.     
  529.     if (hilite&kDateHiliteMask)
  530.     {
  531.         LString::CopyPStr( dateStr, tempStr);
  532.     
  533.         if (hilite == kDayOfWeekItem)
  534.         {
  535.             tempStr[0] = this->mStartArray[1];
  536.             startH = ::StringWidth(tempStr) + startPos.h;
  537.             
  538.             tempStr[0] = this->mEndArray[1];
  539.             endH = ::StringWidth(tempStr) + startPos.h;    
  540.         }
  541.         else if (hilite == kMonthItem)
  542.         {
  543.             tempStr[0] = this->mStartArray[2];
  544.             startH = ::StringWidth(tempStr) + startPos.h;
  545.             
  546.             tempStr[0] = this->mEndArray[2];
  547.             endH = ::StringWidth(tempStr) + startPos.h;
  548.         }
  549.         else if (hilite == kDateItem)
  550.         {
  551.             tempStr[0] = this->mStartArray[0];
  552.             startH = ::StringWidth(tempStr) + startPos.h;
  553.             
  554.             tempStr[0] = this->mEndArray[0];
  555.             endH = ::StringWidth(tempStr) + startPos.h;
  556.         }
  557.         else if (hilite == kYearItem)
  558.         {
  559.             tempStr[0] = this->mStartArray[3];
  560.             startH = ::StringWidth(tempStr) + startPos.h;
  561.             
  562.             tempStr[0] = this->mEndArray[3];
  563.             endH = ::StringWidth(tempStr) + startPos.h;
  564.         }
  565.         ::SetRect(&workRect, startH, strRect.top + 3, 
  566.                              endH, strRect.bottom - 2);
  567.         ::HiliteRect( &workRect );
  568.     }
  569.     
  570.     return ::StringWidth( dateStr );
  571. }
  572. Int16        
  573. LTimeDateControl::FindHotSpot(Point inPoint)
  574. {
  575. Rect    contrlRect, testRect;
  576. Int16    width;
  577. Uint16    theHotSpot = kNoPart;
  578.  
  579.     this->CalcLocalFrameRect( contrlRect );
  580.  
  581.     // first, test up & down arrows
  582.     SetRect(&testRect,    contrlRect.right - kButtonIconWidth, 
  583.                         contrlRect.top + (contrlRect.bottom - contrlRect.top)/2 - kButtonIconHeight/2,
  584.                         contrlRect.right,
  585.                         contrlRect.top + (contrlRect.bottom - contrlRect.top)/2 + kButtonIconHeight/2);
  586.     if (::PtInRect( inPoint, &testRect))
  587.     {
  588.         if ( inPoint.v < (testRect.bottom + testRect.top)/2 )
  589.             return kInUpArrow;
  590.         else
  591.             return kInDownArrow;
  592.     }
  593.     
  594.     // not in arrows so in text?
  595.     
  596.     switch (this->mVariation)
  597.     {
  598.         case kTimeVariation:
  599.             testRect = contrlRect;
  600.             testRect.left += kTimeStringPos;
  601.             testRect.right = contrlRect.right - kTimeStringPos - kButtonIconWidth;
  602.             theHotSpot = this->TestTimeString( testRect, inPoint, width );
  603.             break;
  604.         case kLongDateVariation:
  605.             testRect = contrlRect;
  606.             testRect.left += kTimeStringPos;
  607.             testRect.right = contrlRect.right - kTimeStringPos - kButtonIconWidth;
  608.              theHotSpot = this->TestLongDateString( testRect, inPoint, width );
  609.              break;
  610.          case kLongDateAndTimeVariation:
  611.             testRect = contrlRect;
  612.             testRect.left += kTimeStringPos;
  613.             testRect.right = contrlRect.right - kTimeStringPos - kButtonIconWidth;
  614.              theHotSpot = this->TestLongDateString( testRect, inPoint, width );
  615.              if (!theHotSpot)
  616.              {
  617.                  testRect.left += kTimeStringPos + width;
  618.                  theHotSpot = this->TestTimeString( testRect, inPoint, width );
  619.              }
  620.              break;
  621.     }
  622.     
  623.     if (!theHotSpot)
  624.         this->DontBeTarget();
  625.         
  626.     return theHotSpot;
  627. }
  628.  
  629. void
  630. LTimeDateControl::HotSpotAction(    Int16        inHotSpot,
  631.                                     Boolean        inCurrInside,
  632.                                     Boolean        inPrevInside)
  633. {
  634.  
  635.     if (inCurrInside)
  636.     {
  637.         if ( inHotSpot&kArrowPartMask )
  638.             this->ArrowAction( inHotSpot, (inCurrInside == inPrevInside) );
  639.     }
  640.     else
  641.     {
  642.         this->FocusDraw();
  643.         this->DrawDateTimeControl();
  644.     }
  645.     
  646.  
  647. void
  648. LTimeDateControl::ArrowAction( Uint16 inHotSpot, Boolean holdClick )
  649. {
  650. Uint32        deltaVal;
  651. DateTimeRec    theDate;
  652.  
  653.     if (this->mCurrentHilite&kDateHiliteMask)
  654.         ::SecondsToDate(this->mDateTimeValue, &theDate);
  655.     switch (inHotSpot&kArrowPartMask)
  656.     {
  657.         case kInUpArrow:
  658.             deltaVal = 1;
  659.             break;
  660.         case kInDownArrow:
  661.             deltaVal = -1;
  662.             break;
  663.         default:
  664.             deltaVal = 0;
  665.             break;
  666.     }
  667.     if ( (!holdClick)||( holdClick&&( ::TickCount() > this->mLastClickTickCount + 10 )) )
  668.     {
  669.         this->mLastClickTickCount = ::TickCount();
  670.         switch (this->mCurrentHilite)
  671.         {
  672.             case kMonthItem:
  673.                 theDate.month += deltaVal;
  674.                 break;
  675.             case kDateItem:
  676.             case kDayOfWeekItem:
  677.                 theDate.day += deltaVal;
  678.                 break;
  679.             case kYearItem:
  680.                 theDate.year += deltaVal;
  681.                 break;
  682.             case kHourItem:
  683.                 this->mDateTimeValue += deltaVal*3600;
  684.                 break;
  685.             case kMinuteItem:
  686.                 this->mDateTimeValue += deltaVal*60;
  687.                 break;
  688.             case kSecondItem:
  689.                 this->mDateTimeValue += deltaVal;
  690.                 break;
  691.             case kAMPMItem:
  692.                 this->mDateTimeValue += deltaVal*12*3600;
  693.                 break;
  694.             
  695.         }
  696.     }
  697.     if (this->mCurrentHilite&kDateHiliteMask)
  698.         ::DateToSeconds( &theDate, &this->mDateTimeValue);
  699.     
  700.     this->FocusDraw();
  701.     this->DrawDateTimeControl( inHotSpot );
  702. }
  703.  
  704. void
  705. LTimeDateControl::HotSpotResult( short    inHotSpot)
  706. {
  707.                                                     
  708.     if ( inHotSpot&kTextComponentMask )
  709.         this->mCurrentHilite = inHotSpot&kTextComponentMask;
  710.         
  711.     this->HotSpotAction(inHotSpot, false, true);    // Undo hilighting
  712.     
  713.     if (inHotSpot&kArrowPartMask)
  714.         this->BroadcastMessage( msg_TimeDateHasChanged, (void *)this->GetPaneID() );                //  send message to inform Listeners
  715. }
  716.  
  717. Uint16
  718. LTimeDateControl::TestTimeString( const Rect& strRect, const Point& hitPt, Int16& width )
  719. {
  720. Rect                 partRect;
  721. Str255                timeStr, tempStr;
  722. short                startH, endH;
  723.  
  724.     this->FocusDraw();
  725.     ::TimeString(this->mDateTimeValue, false, timeStr, (Handle)this->mTimeFormatH );
  726.     width = ::StringWidth(timeStr);
  727.  
  728.     if(::PtInRect(hitPt, &strRect)) 
  729.     {
  730.         LString::CopyPStr(timeStr, tempStr);
  731.  
  732.         // Hour Item
  733.         startH = 0;
  734.         tempStr[0] = 2;
  735.         endH = ::StringWidth(tempStr);
  736.         ::SetRect(&partRect,    strRect.left + startH, strRect.top, 
  737.                                 strRect.left + endH, strRect.bottom);
  738.         if (::PtInRect(hitPt, &partRect))
  739.             return kHourItem;
  740.  
  741.         // minute item
  742.         if ((*mTimeFormatH)->timeSep)
  743.         {
  744.             tempStr[0] = 3;
  745.             startH = ::StringWidth(tempStr);
  746.             tempStr[0] = 5;
  747.             endH = ::StringWidth(tempStr);
  748.         }
  749.         else
  750.         {
  751.             tempStr[0] = 2;
  752.             startH = ::StringWidth(tempStr);
  753.             tempStr[0] = 4;
  754.             endH = ::StringWidth(tempStr);
  755.         }
  756.         ::SetRect(&partRect,    strRect.left + startH, strRect.top, 
  757.                                 strRect.left + endH, strRect.bottom);
  758.         if (::PtInRect(hitPt, &partRect))
  759.             return kMinuteItem;
  760.  
  761.         // AM PM item
  762.         if ((*mTimeFormatH)->timeSep)
  763.         {
  764.             tempStr[0] = 6;
  765.             startH = ::StringWidth(tempStr);
  766.             tempStr[0] = 8;
  767.             endH = ::StringWidth(tempStr);
  768.         }
  769.         else
  770.         {
  771.             tempStr[0] = 5;
  772.             startH = ::StringWidth(tempStr);
  773.             tempStr[0] = 7;
  774.             endH = ::StringWidth(tempStr);
  775.         }
  776.         ::SetRect(&partRect,    strRect.left + startH, strRect.top, 
  777.                                 strRect.left + endH, strRect.bottom);
  778.         if (::PtInRect(hitPt, &partRect))
  779.             return kAMPMItem;
  780.  
  781.     }
  782.     return kNoPart;
  783. }
  784.  
  785. Uint16
  786. LTimeDateControl::TestLongDateString( const Rect& strRect, const Point& hitPt, Int16& width )
  787. {
  788. Rect                 partRect;
  789. Str255                dateStr, tempStr;
  790. short                startH, endH;
  791.  
  792.     this->FocusDraw();
  793.     ::DateString( this->mDateTimeValue, abbrevDate, dateStr, (Handle)this->mDateFormatH);
  794.     width = ::StringWidth(dateStr);
  795.     
  796.     if(::PtInRect(hitPt, &strRect)) 
  797.     {
  798.         LString::CopyPStr(dateStr, tempStr);
  799.  
  800.         /* Day Name item */
  801.         tempStr[0] = this->mStartArray[1];
  802.         startH = ::StringWidth(tempStr);
  803.         
  804.         tempStr[0] = this->mEndArray[1];
  805.         endH = ::StringWidth(tempStr);
  806.         ::SetRect(&partRect,    strRect.left + startH, strRect.top, 
  807.                                 strRect.left + endH, strRect.bottom);
  808.         if (::PtInRect(hitPt, &partRect))
  809.             return kDayOfWeekItem;
  810.         
  811.         /* Month Item */    
  812.         tempStr[0] = this->mStartArray[2];
  813.         startH = ::StringWidth(tempStr);
  814.         
  815.         tempStr[0] = this->mEndArray[2];
  816.         endH = ::StringWidth(tempStr);
  817.         ::SetRect(&partRect,    strRect.left + startH, strRect.top, 
  818.                                 strRect.left + endH, strRect.bottom);
  819.         if (::PtInRect(hitPt, &partRect))
  820.             return kMonthItem;
  821.             
  822.         /* date num item */
  823.         tempStr[0] = this->mStartArray[0];
  824.         startH = ::StringWidth(tempStr);
  825.         
  826.         tempStr[0] = this->mEndArray[0];
  827.         endH = ::StringWidth(tempStr);
  828.         ::SetRect(&partRect,    strRect.left + startH, strRect.top, 
  829.                                 strRect.left + endH, strRect.bottom);
  830.         if (::PtInRect(hitPt, &partRect))
  831.             return kDateItem;
  832.         
  833.         /* year item */
  834.         tempStr[0] = this->mStartArray[3];
  835.         startH = ::StringWidth(tempStr);
  836.         
  837.         tempStr[0] = this->mEndArray[3];
  838.         endH = ::StringWidth(tempStr);
  839.         ::SetRect(&partRect,    strRect.left + startH, strRect.top, 
  840.                                 strRect.left + endH, strRect.bottom);
  841.         if (::PtInRect(hitPt, &partRect))
  842.             return kYearItem;
  843.             
  844.     }
  845.  
  846.     return kNoPart;
  847. }
  848. DateTimeRec
  849. LTimeDateControl::GetDateTimeRec( void ) const
  850. {
  851. DateTimeRec        outRec;
  852.  
  853.     ::SecondsToDate( this->mDateTimeValue, &outRec );
  854.     
  855.     return outRec;
  856. }
  857. void
  858. LTimeDateControl::SetDateTimeValue( const DateTimeRec& inRec )
  859. {
  860.     DateToSeconds( &inRec, &this->mDateTimeValue );
  861.     this->Refresh();
  862. }
  863. Uint32
  864. LTimeDateControl::GetDateTimeValue( void ) const
  865. {
  866.     return this->mDateTimeValue;
  867. }
  868. void
  869. LTimeDateControl::SetDateTimeValue( const Uint32& inValue )
  870. {
  871.     this->mDateTimeValue = inValue;
  872.     this->Refresh();
  873. }
  874.  
  875.  
  876.  
  877. static void    HiliteRect(Rect *theRect)
  878. {
  879. unsigned char    oldMode;
  880.  
  881.     oldMode = LMGetHiliteMode();
  882.     LMSetHiliteMode( 1 );
  883.     InvertRect(theRect);
  884.     LMSetHiliteMode( oldMode );
  885. }
  886.  
  887.